package com.whfc.common.idcard;

import com.alibaba.fastjson.JSONObject;
import com.whfc.common.util.HttpUtil;
import com.whfc.common.util.IdCardVerifyUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.TreeMap;

/**
 * @Description 身份证识别工具
 * @Author hw
 * @Date 2021-08-05 10:21
 * @Version 1.0
 */
public class IdentifyUtil {

    private static final Logger logger = LoggerFactory.getLogger(IdCardVerifyUtil.class);

    private final static Charset UTF8 = StandardCharsets.UTF_8;
    private final static String SECRET_ID = "AKID3xd5IH1Zs31lIbiaEeqnVzFH5g2A5mFY";
    private final static String SECRET_KEY = "B9uTpxsc7PULyMWR8b7SaUBfvzpRp21l";
    private final static String CT_JSON = "application/json; charset=utf-8";
    private final static String REGION = "ap-guangzhou";


    private final static String SIGNATURE_ALGORITHM = "TC3-HMAC-SHA256";

    private final static String IDENTIFY_HOST = "ocr.tencentcloudapi.com";
    private final static String IDENTIFY_SERVICE = "ocr";
    private final static String IDENTIFY_ACTION = "IDCardOCR";
    private final static String IDENTIFY_VERSION = "2018-11-19";

    public static IdentifyDTO identify(String imgUrl, String base64Str) {
        JSONObject json = new JSONObject();
        if (StringUtils.isNotEmpty(imgUrl)) {
            json.put("ImageUrl", imgUrl);
        } else {
            json.put("ImageUrl", base64Str);
        }
        JSONObject config = new JSONObject();
        config.put("CropPortrait", true);
        config.put("CopyWarn", true);
        config.put("BorderCheckWarn", true);
        config.put("ReshootWarn", true);
        config.put("DetectPsWarn", true);
        config.put("TempIdWarn", true);
        config.put("InvalidDateWarn", true);
        json.put("Config", config.toJSONString());
        try {
            TreeMap<String, String> headers = getHeaders(json.toJSONString());
            String resp = HttpUtil.doPost("https://" + IDENTIFY_HOST, json.toJSONString(), headers);
            logger.info("证件识别,response:{}", resp);
            JSONObject respJson = JSONObject.parseObject(resp);
            if (resp.contains("Error")) {
                return null;
            }
            IdentifyDTO identifyDTO = JSONObject.parseObject(respJson.getString("Response"), IdentifyDTO.class);
            return identifyDTO;
        } catch (Exception e) {
            logger.error("身份证识别失败", e);
        }
        return null;
    }


    private static TreeMap<String, String> getHeaders(String payload) throws Exception {
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 注意时区，否则容易出错
        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
        String date = sdf.format(new Date(Long.parseLong(timestamp + "000")));

        // ************* 步骤 1：拼接规范请求串 *************
        String httpRequestMethod = "POST";
        String canonicalUri = "/";
        String canonicalQueryString = "";
        String canonicalHeaders = "content-type:application/json; charset=utf-8\n" + "host:" + IDENTIFY_HOST + "\n";
        String signedHeaders = "content-type;host";

        String hashedRequestPayload = sha256Hex(payload);
        String canonicalRequest = httpRequestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n" + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;

        // ************* 步骤 2：拼接待签名字符串 *************
        String credentialScope = date + "/" + IDENTIFY_SERVICE + "/" + "tc3_request";
        String hashedCanonicalRequest = sha256Hex(canonicalRequest);
        String stringToSign = SIGNATURE_ALGORITHM + "\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;

        // ************* 步骤 3：计算签名 *************
        byte[] secretDate = hmac256(("TC3" + SECRET_KEY).getBytes(UTF8), date);
        byte[] secretService = hmac256(secretDate, IDENTIFY_SERVICE);
        byte[] secretSigning = hmac256(secretService, "tc3_request");
        String signature = DatatypeConverter.printHexBinary(hmac256(secretSigning, stringToSign)).toLowerCase();

        // ************* 步骤 4：拼接 Authorization *************
        String authorization = SIGNATURE_ALGORITHM + " " + "Credential=" + SECRET_ID + "/" + credentialScope + ", " + "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
        System.out.println(authorization);
        TreeMap<String, String> headers = new TreeMap<>();
        headers.put("Authorization", authorization);
        headers.put("Content-Type", CT_JSON);
        headers.put("Host", IDENTIFY_HOST);
        headers.put("X-TC-Action", IDENTIFY_ACTION);
        headers.put("X-TC-Timestamp", timestamp);
        headers.put("X-TC-Version", IDENTIFY_VERSION);
        headers.put("X-TC-Region", REGION);
        return headers;
    }


    private static byte[] hmac256(byte[] key, String msg) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
        mac.init(secretKeySpec);
        return mac.doFinal(msg.getBytes(UTF8));
    }

    private static String sha256Hex(String s) throws Exception {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] d = md.digest(s.getBytes(UTF8));
        return DatatypeConverter.printHexBinary(d).toLowerCase();
    }

}
